package com.ea.eadp.nexus.test.common.ApiClients;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.ea.eadp.nexus.client.nucleus.identity.model.*;
import com.ea.eadp.nexus.client.nucleus.identity.model.FailureType;
import com.ea.eadp.nexus.client.nucleus.identity.model.PidPersonaType;
import com.ea.eadp.nexus.client.nucleus.identity.model.PidType;
import com.ea.eadp.nexus.client.nucleus.identity.model.PutPersonaRequestType;
import com.ea.eadp.nexus.test.common.*;
import com.ea.eadp.rest.identity.generated.*;
import com.ea.eadp.rest.identity.generated.MachineProfileResponseType;
import com.ea.eadp.rest.identity.generated.PSNAccessTokenType;
import com.ea.eadp.rest.identity.generated.PidGamePersonaMappingType;
import com.ea.eadp.rest.identity.generated.PidGamePersonaMappingsType;
import com.ea.eadp.rest.identity.generated.TwoFactorType;
import com.ea.nucleus.eaid.impl.psntoken.PSNAccessTokenImpl;
import com.ea.nucleus.eaid.psntoken.PSNAccessToken;
import org.apache.commons.io.IOUtils;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.CookieStore;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.protocol.ClientContext;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.EntityUtils;
import org.testng.Assert;

import com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException;

/**
 * Created by ChuanYe on 7/24/2014.
 */
public class NexusGatewayApi extends NexusApiBase {
    private static NexusGatewayApi instance;

    public synchronized static NexusGatewayApi instance() {
        if(instance == null) {
            instance = new NexusGatewayApi();
        }
        instance.client = NexusHttpClients.getGatewayClient();
        return instance;
    }

    private static String HttpsProxyBaseUri = TestUtil.BaseHttpsProxyURI();
    private static String HttpProxyInternalBaseUri = TestUtil.BaseHttpProxyInternalURI();
    private static String ProxyBaseUri = TestUtil.BaseProxyURI();

    public void invokeNucleusApi(AccessToken token, TokenInfo tokenInfo) throws Exception {
        HttpGet httpGet = new HttpGet(ProxyBaseUri + "/proxy/identity/pids/" + tokenInfo.getPid_id());
        httpGet.setHeader("Authorization", token.getToken_type() + " " + token.getAccess_token());
        HttpResponse response = get(httpGet, null); //client.execute(httpGet);
        String pid = IOUtils.toString(response.getEntity().getContent());
        log.info(pid);
        PidType pidType = TestUtil.parseJson(pid, PidType.class, "pid");
        if (!pidType.getPidId().toString().equals(tokenInfo.getPid_id())) {
            throw new Exception("pids not match");
        }
    }

    public void invokeNucleusApiByServer(AccessToken token, String pid) throws Exception {

        HttpGet httpGet = new HttpGet(ProxyBaseUri + "/proxy/identity/pids/" + pid);
        httpGet.setHeader("Authorization", token.getToken_type() + " " + token.getAccess_token());
        HttpResponse response = get(httpGet, null);//client.execute(httpGet);
        String pidString = IOUtils.toString(response.getEntity().getContent());
        log.info(pidString);
        PidType pidType = TestUtil.parseJson(pidString, PidType.class, "pid");
        if (!pidType.getPidId().toString().equals(pid)) {
            throw new Exception("pids not match");
        }
    }

    public PermissionInfoType getPermissionInfo(AccessToken accessToken, String personaId, String env, String platForm) throws Exception
    {
        return getPermissionInfo(accessToken, personaId, env, platForm, null);
    }
    public PermissionInfoType getPermissionInfo(AccessToken accessToken, String personaId, String env, String platForm, String ps4ticket) throws Exception
    {
        HashMap<String, String> hashMap = new HashMap<String, String>();
        hashMap.put("personaId", personaId);

        String queryString = String.format("environment=%s&platform=%s", env, platForm);
        if (ps4ticket != null) queryString += "&ps4_ticket=" + ps4ticket;

        String response = this.get(accessToken, NexusGatewayApiEnum.persona_permissioninfo_get_by_personaid, hashMap, queryString, false);
        log.info(response);

        return TestUtil.parseJson(response, PermissionInfoType.class, "PermissionInfo");
    }

    public PSNAccessTokenType getPsnAccessToken(AccessToken accessToken, String personaId) throws Exception {
        return getPsnAccessToken(accessToken, personaId, null);
    }

    public PSNAccessTokenType getPsnAccessToken(AccessToken accessToken, String personaId, String ps4ticket) throws Exception {
        HashMap<String, String> hashMap = new HashMap<String, String>();
        hashMap.put("personaId", personaId);

        String response = this.get(accessToken, NexusGatewayApiEnum.persona_psnaccesstoken_get_by_personaid, hashMap, ps4ticket == null ? null : "ps4_ticket="+ps4ticket, false);
        log.info(response);

        return TestUtil.parseJson(response, PSNAccessTokenType.class, "psnAccessToken");
    }

    public PidInfos getPidInfosByExternalRefIds(String accessToken, String pidType, String client_id, List<String> externalRefIdList) throws Exception {

        String content = "{\n" +
                "\"pidType\": \"" + pidType + "\",\n" +
                "\"clientId\": \"" + client_id + "\",\n" +
                "\"values\": [\n";
        for(String externalRefId : externalRefIdList) {
            content += "\"";
            content += externalRefId;
            content += "\",\n";
        }
        content = content.substring(0, content.length()-2);
        content += "\n]\n}";
        //nameValuePairs.add(new BasicNameValuePair("pidType", pidType));
        //nameValuePairs.add(new BasicNameValuePair("clientId", client_id));
        //nameValuePairs.add(new BasicNameValuePair("values", externalRefIds));

        CookieStore cookieStore = new BasicCookieStore();
        HttpContext httpContext = new BasicHttpContext();
        httpContext.setAttribute(ClientContext.COOKIE_STORE, cookieStore);
        HttpPost httpPost = new HttpPost(ProxyBaseUri + "/proxy/identity/pids/personaextref/bulk");
        httpPost.setEntity(new StringEntity(content, ContentType.APPLICATION_JSON));

        HashMap<String, String> headers = new HashMap<String, String>();
        headers.put("Authorization","Bearer " + accessToken);
        for(Map.Entry<String, String> entry : headers.entrySet()) {
            httpPost.addHeader(entry.getKey(),entry.getValue());
        }
        httpPost.addHeader("content-type", "application/raw");
        HttpResponse response = post(httpPost, httpContext);// client.execute(httpPost, httpContext);
        String pidInfosString = IOUtils.toString(response.getEntity().getContent());
        log.info(pidInfosString);
        try {
            return TestUtil.parseJson(pidInfosString, PidInfos.class);
        } catch (UnrecognizedPropertyException e) {
            log.info(e.getMessage());
            throw new Exception(pidInfosString);
        }
    }

    public List<PidPersonaType> getPersonas(AccessToken token, String pid) throws Exception {

        HttpGet httpGet = new HttpGet(ProxyBaseUri +
                "/proxy/identity/pids/" + pid + "/personas?status=ACTIVE");
        httpGet.setHeader("Authorization", token.getToken_type() + " " + token.getAccess_token());
        httpGet.setHeader("X-Expand-Results", "true");
        httpGet.setHeader("X-Include-Underage", "true");
        HttpResponse response = get(httpGet, null);//client.execute(httpGet);
        String entity = IOUtils.toString(response.getEntity().getContent());
        log.info(entity);
        return TestUtil.parseJson(entity, PersonasInfo.class, "personas").getPersona();
    }

    public HttpResponse putPersona(AccessToken token, String pid, String personaId, PutPersonaRequestType putPersonaRequestType) throws Exception {
        HttpPut httpPut = new HttpPut(ProxyBaseUri +
                "/proxy/identity/pids/" + pid + "/personas/" + personaId);
        httpPut.setHeader("Authorization", token.getToken_type() + " " + token.getAccess_token());
        String content = TestUtil.parseObject(putPersonaRequestType);
        httpPut.setEntity(new StringEntity(content, ContentType.APPLICATION_JSON));
        HttpResponse response = put(httpPut, null);//client.execute(httpGet);
        String body = IOUtils.toString(response.getEntity().getContent());
        if (response.getStatusLine().getStatusCode()!=200){
            throw new Exception(body);
        }
        return response;
    }

    public PidType getPidsMe(AccessToken token) throws Exception {

        HttpGet httpGet = new HttpGet(ProxyBaseUri +
                "/proxy/identity/pids/me");
        httpGet.setHeader("Authorization", token.getToken_type() + " " + token.getAccess_token());
        httpGet.setHeader("X-Include-Underage", "true");
        httpGet.setHeader("X-Include-Incomplete","true");
        HttpResponse response = get(httpGet, null);//client.execute(httpGet);
        String entity = IOUtils.toString(response.getEntity().getContent());
        log.info(entity);
        return TestUtil.parseJson(entity, PidType.class, "pid");
    }

    public PidType getPid(AccessToken token, long pidId) throws Exception {

        HttpGet httpGet = new HttpGet(ProxyBaseUri +
                "/proxy/identity/pids/" + pidId);
        httpGet.setHeader("Authorization", token.getToken_type() + " " + token.getAccess_token());
        httpGet.setHeader("X-Include-Underage", "true");
        HttpResponse response = get(httpGet, null);//client.execute(httpGet);
        String entity = IOUtils.toString(response.getEntity().getContent());
        log.info(entity);
        return TestUtil.parseJson(entity, PidType.class, "pid");
    }

    public List<PidGamePersonaMappingType> getTokenLinkedPersonas(AccessToken token) throws Exception {
        String url = ProxyBaseUri +
                "/proxy/identity/links"  + "?access_token=" + token.getAccess_token();

        HttpGet httpGet = new HttpGet(url);
        HttpResponse response = get(httpGet, null);
        int statusCode=response.getStatusLine().getStatusCode();
        if (statusCode != 200) {
            throw new Exception(EntityUtils.toString(response.getEntity(), "UTF-8"));
        }

        String responseMessage = null;

        if (response.getEntity() != null) {
            responseMessage = EntityUtils.toString(response.getEntity(), "UTF-8");
        }

        if (responseMessage == null) {
            throw new Exception("Null response returned for getCodeByMobileUpidToken");
        }

        try {
            PidGamePersonaMappingsType pidGamePersonaMappingsType = TestUtil.parseJson(responseMessage, PidGamePersonaMappingsType.class, "pidGamePersonaMappings");
            List<PidGamePersonaMappingType> pidGamePersonaMappingsList = pidGamePersonaMappingsType.getPidGamePersonaMapping();
            return pidGamePersonaMappingsList;
        }
        catch (Exception e) {
            throw new Exception(e.getMessage());
        }

    }

    public PidPersonaType getPersonas(AccessToken token, String pid, String personasId) throws Exception {

        HttpGet httpGet = new HttpGet(ProxyBaseUri +
                "/proxy/identity/pids/" + pid + "/personas/" + personasId);
        httpGet.setHeader("Authorization", token.getToken_type() + " " + token.getAccess_token());
        HttpResponse response = get(httpGet, null);//client.execute(httpGet);
        String entity = IOUtils.toString(response.getEntity().getContent());
        log.info(entity);
        return TestUtil.parseJson(entity, PidPersonaType.class, "persona");
    }

    public void resendRegistrationCode(AccessToken token, String email, String platform,Map<String,String> headers) throws Exception {
        HttpGet httpGet = new HttpGet(ProxyBaseUri +
                "/proxy/identity/progregist/code?email="+email+"&platform="+platform);
        httpGet.setHeader("Authorization", token.getToken_type() + " " + token.getAccess_token());
        if (headers!=null){
            for (String key :headers.keySet()){
                httpGet.setHeader(key, headers.get(key));

            }
        }
        HttpResponse response = get(httpGet, null);//client.execute(httpGet);
        String body = IOUtils.toString(response.getEntity().getContent());
        if (response.getStatusLine().getStatusCode()!=200){
            throw new Exception(body);
        }

    }
    public void resendRegistrationCode(AccessToken token, String email, String platform) throws Exception {
        HttpGet httpGet = new HttpGet(ProxyBaseUri +
                "/proxy/identity/progregist/code?email="+email+"&platform="+platform);
        httpGet.setHeader("Authorization", token.getToken_type() + " " + token.getAccess_token());
        httpGet.setHeader("X-SEND-CODE", "true");
        HttpResponse response = get(httpGet, null);//client.execute(httpGet);
        String body = IOUtils.toString(response.getEntity().getContent());
        if (response.getStatusLine().getStatusCode()!=200){
            throw new Exception(body);
        }
    }

    public DeviceUserLinksType getDeviceLinksByPid(AccessToken token,String pid, String namespace) throws Exception {
        String url = HttpProxyInternalBaseUri + "/proxy/identity/pids/" +pid+ "/devicelinks?status=ALL";
        if(namespace!=null)
            url += "&namespace="+namespace;
        HttpGet httpGet = new HttpGet(url);
        httpGet.setHeader("Authorization", token.getToken_type() + " " + token.getAccess_token());
        HttpResponse response = get(httpGet, null);//client.execute(httpGet);
        String body = IOUtils.toString(response.getEntity().getContent());
        if (response.getStatusLine().getStatusCode()!=200){
            if (body.contains("NO_SUCH_LINK"))
                return  null;
            throw new Exception(body);
        }
        try{
            return TestUtil.parseJson(body, DeviceUserLinksType.class, "deviceUserLinks");
        }
        catch(Exception e){
            throw new Exception(e.getMessage());
        }
    }
    public String getTwoFactorStatus(AccessToken token,String pid) throws Exception{
        HttpGet httpGet = new HttpGet(HttpProxyInternalBaseUri + "/proxy/identity/pids/" + pid+"/twofactor");
        if (token != null){
            httpGet.setHeader("Authorization", token.getToken_type() + " " + token.getAccess_token());
        }
        HttpResponse response = get(httpGet, null);
        String body = IOUtils.toString(response.getEntity().getContent());
        if (response.getStatusLine().getStatusCode()!=200){
            throw new Exception(body);
        }
        try{
            return TestUtil.parseJson(body, TwoFactorType.class, "twoFactor").getStatus();
        }
        catch(Exception e){
            throw new Exception(body);
        }
    }

    public String getTwoFactorCode(AccessToken token,String pid) throws Exception {
            return getTwoFactorCodeWithHeader(token,pid,null);
    }
    public String getTwoFactorCodeWithHeader(AccessToken token,String pid,Map<String,String> headers) throws Exception {
        HttpGet httpGet = new HttpGet(HttpProxyInternalBaseUri + "/proxy/identity/pids/" + pid+"/twofactor/code");
        if (token != null){
            httpGet.setHeader("Authorization", token.getToken_type() + " " + token.getAccess_token());
        }
        if (headers!=null){
                for (String key :headers.keySet()){
                    httpGet.setHeader(key, headers.get(key));

                }
            }
        HttpResponse response = get(httpGet, null);
        String body = IOUtils.toString(response.getEntity().getContent());
        log.info(body);
        if (response.getStatusLine().getStatusCode()!=200){
               throw new Exception(body);
        }
        try{
            return TestUtil.parseJson(body).get("twoFactorCode");
        }
        catch(Exception e){
            throw new Exception(body);
        }
    }
    public String verifyTwoFactorCode(AccessToken token,String pid, String code,String codeType) throws Exception {
        String content = "{\"code\":\""+code+"\",\""+
                "codeType\":\""+codeType+
                "\"}";
        CookieStore cookieStore = new BasicCookieStore();
        HttpContext httpContext = new BasicHttpContext();
        httpContext.setAttribute(ClientContext.COOKIE_STORE, cookieStore);
        HttpPost httpPost = new HttpPost(HttpProxyInternalBaseUri + "/proxy/identity/pids/" + pid+"/twofactor/verify");
        httpPost.setEntity(new StringEntity(content, ContentType.APPLICATION_JSON));

        HashMap<String, String> headers = new HashMap<String, String>();
        if (token != null){
        headers.put("Authorization", token.getToken_type() + " " + token.getAccess_token());
        }
        headers.put("Content-Type","application/json");
        for(Map.Entry<String, String> entry : headers.entrySet()) {
            httpPost.addHeader(entry.getKey(),entry.getValue());
        }
        HttpResponse response = post(httpPost, httpContext);// client.execute(httpPost, httpContext);
        String body = IOUtils.toString(response.getEntity().getContent());
        log.info(body);
        if (response.getStatusLine().getStatusCode()!=200){
            throw new Exception(body);
        }
        try {
            return TestUtil.parseJson(body).get("codeStatus");
        } catch (Exception e) {
            log.info(e.getMessage());
            throw new Exception(body);
        }
    }
    public Machineprofiles getMachineprofile(AccessToken token, String pid, boolean X_Expand_Results) throws Exception {
        HttpGet httpGet = new HttpGet(HttpProxyInternalBaseUri + "/proxy/identity/pids/" + pid + "/machineprofile");
        if (token != null) {
            httpGet.setHeader("Authorization", token.getToken_type() + " " + token.getAccess_token());
        }
        if (X_Expand_Results) {
            httpGet.setHeader("X-Nucleus-MachineProfile-ViaId", "true");
        } else {
            httpGet.setHeader("X-Nucleus-MachineProfile-ViaId", "false");
        }

        HttpResponse response = get(httpGet, null);
        String body = IOUtils.toString(response.getEntity().getContent());
        log.info(body);
        if (response.getStatusLine().getStatusCode()!=200){
            throw new Exception(body);
        }
        try {
            return TestUtil.parseJson(body, Machineprofiles.class, "machineProfileV2ItemsResponse");
        } catch (Exception e) {
            log.info(e.getMessage());
            throw new Exception(body);
        }
    }
    public MachineProfileVerifyResponse getMachineprofileVerify(AccessToken token, String pid, String userIp,Map<String,String> headers) throws Exception {
        HttpGet httpGet = new HttpGet(HttpProxyInternalBaseUri + "/proxy/identity/pids/" + pid + "/machineprofile/verify");
        if (token != null) {
            httpGet.setHeader("Authorization", token.getToken_type() + " " + token.getAccess_token());
        }
        if (userIp!=null) {
            httpGet.setHeader("X-Nucleus-User-IP", userIp);
        }
        if (headers!=null){
            for (String key :headers.keySet()){
                httpGet.setHeader(key, headers.get(key));

            }
        }
        HttpResponse response = get(httpGet, null);
        String body = IOUtils.toString(response.getEntity().getContent());
        log.info(body);

        try {
            return TestUtil.parseJson(body, MachineProfileVerifyResponse.class);
        } catch (Exception e) {
            log.info(e.getMessage());
            throw new Exception(body);
        }
    }
        public MachineProfileVerifyResponse getMachineprofileVerify(AccessToken token, String pid, String userIp) throws Exception {
        HttpGet httpGet = new HttpGet(HttpProxyInternalBaseUri + "/proxy/identity/pids/" + pid + "/machineprofile/verify");
        if (token != null) {
            httpGet.setHeader("Authorization", token.getToken_type() + " " + token.getAccess_token());
        }
        if (userIp!=null) {
            httpGet.setHeader("X-Nucleus-User-IP", userIp);
        }

        HttpResponse response = get(httpGet, null);
        String body = IOUtils.toString(response.getEntity().getContent());
        log.info(body);

        try {
            return TestUtil.parseJson(body, MachineProfileVerifyResponse.class);
        } catch (Exception e) {
            log.info(e.getMessage());
            throw new Exception(body);
        }
    }

    public MachineProfileVerifyResponse getMachineprofileVerifyWithLocale(AccessToken token, String pid, String locale) throws Exception {
        String uri=HttpProxyInternalBaseUri + "/proxy/identity/pids/" + pid + "/machineprofile/verify";
        if (locale!=null) {
            uri+="?locale="+locale;
        }
        HttpGet httpGet = new HttpGet(uri);
        if (token != null) {
            httpGet.setHeader("Authorization", token.getToken_type() + " " + token.getAccess_token());
        }
        HttpResponse response = get(httpGet, null);
        String body = IOUtils.toString(response.getEntity().getContent());
        log.info(body);

        try {
            return TestUtil.parseJson(body, MachineProfileVerifyResponse.class);
        } catch (Exception e) {
            log.info(e.getMessage());
            throw new Exception(body);
        }
    }

    public MachineProfileVerifyResponse postMachineprofileVerify(AccessToken token, String pid, String userIp, String code) throws Exception {
        HttpPost httpPost = new HttpPost(HttpProxyInternalBaseUri + "/proxy/identity/pids/" + pid + "/machineprofile/verify");


        HashMap<String, String> headers = new HashMap<String, String>();
        if (token != null) {
            headers.put("Authorization", token.getToken_type() + " " + token.getAccess_token());
        }
        if (userIp!=null) {
            httpPost.setHeader("X-Nucleus-User-IP", userIp);
        }
        headers.put("Content-Type", "application/json");

        for (Map.Entry<String, String> entry : headers.entrySet()) {
            httpPost.addHeader(entry.getKey(), entry.getValue());
        }

        String content = "{\"code\":\"" + code + "\"}";

        httpPost.setEntity(new StringEntity(content, ContentType.APPLICATION_JSON));

        HttpResponse response = post(httpPost, null);// client.execute(httpPost, httpContext);
        String body = IOUtils.toString(response.getEntity().getContent());
        log.info(body);
        try{
        return TestUtil.parseJson(body, MachineProfileVerifyResponse.class);
        }catch (Exception e) {
            throw new Exception(body);
        }
    }

    public MachineProfileResponseType getMachineprofile(AccessToken token, String pid,String machineProfile,String platformType,String profileType,boolean X_Expand_Results) throws Exception {
        String oneboxurl=HttpProxyInternalBaseUri + "/proxy/identity/pids/" + pid + "/machineprofile";
        if (platformType != null) {
            oneboxurl+="?platformType="+platformType;
        }
        if (profileType != null) {
            oneboxurl+="&profileType="+profileType;
        }
        if (machineProfile != null) {
            oneboxurl+="&machineProfile="+machineProfile;
        }
        HttpGet httpGet = new HttpGet(oneboxurl);
        if (token != null) {
            httpGet.setHeader("Authorization", token.getToken_type() + " " + token.getAccess_token());
        }

        if (X_Expand_Results) {
            httpGet.setHeader("X-Nucleus-MachineProfile-ViaId", "true");
        } else {
            httpGet.setHeader("X-Nucleus-MachineProfile-ViaId", "false");
        }

        HttpResponse response = get(httpGet, null);
        String body = IOUtils.toString(response.getEntity().getContent());
        log.info(body);
        if (response.getStatusLine().getStatusCode()!=200){
            throw new Exception(body);
        }
        try {
            return TestUtil.parseJson(body, MachineProfileResponseType.class, "machineProfileResponse");
        } catch (Exception e) {
            throw new Exception(body);
        }
    }

    public int putMachineprofile(AccessToken token, String pid, String deviceId, String platformType, String profileType, boolean verified) throws Exception {
        String content = "{\n" +
                "    \"platformType\": \"" + platformType + "\",\n" +
                "    \"profileType\": \"" + profileType + "\",\n" +
                "    \"machineProfile\": \"" + deviceId + "\"";
        if (verified) {
            content += ",\"status\":" + "\"VERIFIED\"";
        }
        content += "\n}";

        CookieStore cookieStore = new BasicCookieStore();
        HttpContext httpContext = new BasicHttpContext();
        httpContext.setAttribute(ClientContext.COOKIE_STORE, cookieStore);
        HttpPut httpPut = new HttpPut(HttpProxyInternalBaseUri + "/proxy/identity/pids/" + pid + "/machineprofile");
        httpPut.setEntity(new StringEntity(content, ContentType.APPLICATION_JSON));

        HashMap<String, String> headers = new HashMap<String, String>();
        if (token != null) {
            headers.put("Authorization", token.getToken_type() + " " + token.getAccess_token());
        }
        headers.put("Content-Type", "application/json");

        for (Map.Entry<String, String> entry : headers.entrySet()) {
            httpPut.addHeader(entry.getKey(), entry.getValue());
        }
        HttpResponse response = put(httpPut, httpContext);// client.execute(httpPost, httpContext);
        String body = IOUtils.toString(response.getEntity().getContent());
        log.info(body);
        if (response.getStatusLine().getStatusCode() != 200) {
            throw new Exception(body);
        }
        return response.getStatusLine().getStatusCode();

    }

    public int postMachineprofile(AccessToken token, String pid, String deviceId, String platformType, String profileType) throws Exception {
       return postMachineprofile(token, pid, deviceId, platformType, profileType, false);
    }

    public int postMachineprofile(AccessToken token, String pid, String deviceId, String platformType, String profileType, boolean verified) throws Exception {
        String content = "{\n" +
                "    \"platformType\": \"" + platformType + "\",\n" +
                "    \"profileType\": \"" + profileType + "\",\n" +
                "    \"machineProfile\": \"" + deviceId + "\"";
        if (verified) {
            content += ",\n\"status\":" + "\"VERIFIED\"";
        }
        content += "\n}";

        CookieStore cookieStore = new BasicCookieStore();
        HttpContext httpContext = new BasicHttpContext();
        httpContext.setAttribute(ClientContext.COOKIE_STORE, cookieStore);
        HttpPost httpPost = new HttpPost(HttpProxyInternalBaseUri + "/proxy/identity/pids/" + pid + "/machineprofile");
        httpPost.setEntity(new StringEntity(content, ContentType.APPLICATION_JSON));

        HashMap<String, String> headers = new HashMap<String, String>();
        if (token != null) {
            headers.put("Authorization", token.getToken_type() + " " + token.getAccess_token());
        }
        headers.put("Content-Type", "application/json");
        for (Map.Entry<String, String> entry : headers.entrySet()) {
            httpPost.addHeader(entry.getKey(), entry.getValue());
        }
        HttpResponse response = post(httpPost, httpContext);// client.execute(httpPost, httpContext);
        String body = IOUtils.toString(response.getEntity().getContent());
        log.info(body);
        if (response.getStatusLine().getStatusCode() != 200) {
            throw new Exception(body);
        }
        return response.getStatusLine().getStatusCode();

    }

    public List<PidGamePersonaMappingType> getLinkedPersonas(AccessToken token, String authenticatorPid, String personaNamespace, String status) throws Exception {
        String url = ProxyBaseUri +
                "/proxy/identity/links/pids/" + authenticatorPid + "?personaNamespace=" + personaNamespace;
        if(status!=null)
            url += ("&status="+status);
        HttpGet httpGet = new HttpGet(url);
        httpGet.setHeader("Authorization", token.getToken_type() + " " + token.getAccess_token());
        HttpResponse response = get(httpGet, null);//client.execute(httpGet);
        String entity = IOUtils.toString(response.getEntity().getContent());
        log.info(entity);
        try {
            PidGamePersonaMappingsType pidGamePersonaMappingsType = TestUtil.parseJson(entity, PidGamePersonaMappingsType.class, "pidGamePersonaMappings");
            List<PidGamePersonaMappingType> pidGamePersonaMappingsList = pidGamePersonaMappingsType.getPidGamePersonaMapping();
            return pidGamePersonaMappingsList;
        }
        catch (Exception e) {
            log.info(e.getMessage());
            throw new Exception(response.getStatusLine().getStatusCode() + " " + entity);
        }
    }

    public List<PidGamePersonaMappingType> getMeLinkedPersonas(AccessToken token, String personaNamespace, String status) throws Exception {
        return getLinkedPersonas(token, "me", personaNamespace, status);
    }

    public void deleteLinkedPersonas(AccessToken token, String authenticatorPid, String personaId) throws Exception {
        String url = ProxyBaseUri +
                "/proxy/identity/links/pids/" + authenticatorPid + "/personas/" + personaId;

        HttpDelete httpDelete = new HttpDelete(url);
        httpDelete.setHeader("Authorization", token.getToken_type() + " " + token.getAccess_token());
        HttpResponse response = delete(httpDelete, null);//client.execute(httpGet);
        String body = IOUtils.toString(response.getEntity().getContent());
        if (response.getStatusLine().getStatusCode()!=200){
            throw new Exception(body);
        }
    }

    public PidType getPidFromProxyWithCert(String keyStoreName, String pid, String client_id) throws Exception{
        HttpsClient httpsClient = NexusHttpClients.getHttpsClient(keyStoreName);
        HttpGet httpGet = new HttpGet(HttpsProxyBaseUri + "/proxy/identity/pids/" + pid);
        if (client_id != null){
            httpGet.setHeader("client_id", client_id);
        }
        HttpResponse response = httpsClient.execute(httpGet);
        String body = IOUtils.toString(response.getEntity().getContent());
        try{
            return TestUtil.parseJson(body, PidType.class, "pid");
        }
        catch(Exception e){
            throw new Exception(body);
        }
    }

    public String post(AccessToken token, NexusGatewayApiEnum api, HashMap<String, String> context, Object object) throws Exception {
        HttpPost httpPost = new HttpPost(initUrl(api, context));
        setHeaders(httpPost, token);
        if (api.getFormat() == "xml") {
            httpPost.setEntity(new StringEntity(TestUtil.parseObjectXml(object)));
            httpPost.addHeader("Accept", "application/xml");
        } else {
            httpPost.setEntity(new StringEntity(TestUtil.parseObject(object)));
            httpPost.addHeader("Accept", "application/json");
        }

        return parseResponse(post(httpPost, null), api);
    }

    public String get(AccessToken token, NexusGatewayApiEnum api, HashMap<String, String> context) throws Exception {
        return get(token, api, context, null);
    }

    public String get(AccessToken token, NexusGatewayApiEnum api, HashMap<String, String> context, Map<String, String> headers) throws Exception {
        HttpGet httpGet = new HttpGet(initUrl(api, context));

        if (null != headers) {
            for (Map.Entry<String, String> header : headers.entrySet()) {
                httpGet.addHeader(header.getKey(), header.getValue());
            }
        }

        setHeaders(httpGet, token);

        return parseResponse(get(httpGet, null), api);
    }

    public String get(AccessToken token, NexusGatewayApiEnum api, HashMap<String, String> context, String queryString,boolean expandResults) throws Exception {
        HttpGet httpGet = new HttpGet(initUrl(api, context, queryString));

        setHeaders(httpGet, token, expandResults);


        return parseResponse(get(httpGet, null), api);
    }

    public String get(AccessToken token, NexusGatewayApiEnum api, HashMap<String, String> context, boolean valid, String error) throws Exception {
        HttpGet httpGet = new HttpGet(initUrl(api, context));
        setHeaders(httpGet, token);

        return parseResponse(get(httpGet, null), valid, error);
    }

    public String delete(AccessToken token, NexusGatewayApiEnum api, HashMap<String, String> context, boolean valid, String error) throws Exception {
        HttpDelete httpDelete = new HttpDelete(initUrl(api, context));
        setHeaders(httpDelete, token);

        return parseResponse(delete(httpDelete, null), valid, error);
    }


    public String get(String signupEmail, String signupPassword, NexusGatewayApiEnum api, HashMap<String, String> context) throws Exception {
        get(signupEmail, signupPassword, api, context, false);
        return get(signupEmail, signupPassword, api, context, true);
    }

    public String get(String signupEmail, String signupPassword, NexusGatewayApiEnum api, HashMap<String, String> context, boolean valid) throws Exception {
        AccessToken token = NexusConnectApi.instance().getAccessTokenWithScope(
                valid ? api.getScope().getName() : Scope.getInvalidScope(api.getScope()).getName(),
                signupEmail, signupPassword);
        HttpGet httpGet = new HttpGet(initUrl(api, context));
        setHeaders(httpGet, token);

        return parseResponse(get(httpGet, null), api, valid, null);
    }

    public String get(String signupEmail, String signupPassword, NexusGatewayApiEnum api, HashMap<String, String> context, boolean valid, String error) throws Exception {
        AccessToken token = NexusConnectApi.instance().getAccessTokenWithScope(
                valid ? api.getScope().getName() : Scope.getInvalidScope(api.getScope()).getName(),
                signupEmail, signupPassword);
        HttpGet httpGet = new HttpGet(initUrl(api, context));
        setHeaders(httpGet, token);

        return parseResponse(get(httpGet, null), api, valid, null);
    }


    public String delete(String signupEmail, String signupPassword, NexusGatewayApiEnum api, HashMap<String, String> context) throws Exception {
        delete(signupEmail, signupPassword, api, context, false);
        return delete(signupEmail, signupPassword, api, context, true);
    }

    public String delete(String signupEmail, String signupPassword, NexusGatewayApiEnum api, HashMap<String, String> context, boolean valid) throws Exception {
        AccessToken token = NexusConnectApi.instance().getAccessTokenWithScope(
                valid ? api.getScope().getName() : Scope.getInvalidScope(api.getScope()).getName(),
                signupEmail, signupPassword);
        HttpDelete httpDelete = new HttpDelete(initUrl(api, context));
        setHeaders(httpDelete, token);

        return parseResponse(delete(httpDelete, null), api, valid, null);
    }

    public String post(String signupEmail, String signupPassword, NexusGatewayApiEnum api, HashMap<String, String> context, Object object) throws Exception {
        return post(signupEmail, signupPassword, api, context, object, null);
    }
    public String post(String signupEmail, String signupPassword, NexusGatewayApiEnum api, HashMap<String, String> context, Object object, List<NameValuePair> additonalHeaders) throws Exception {
        post(signupEmail, signupPassword, api, context, object, false, additonalHeaders);
        return post(signupEmail, signupPassword, api, context, object, true, additonalHeaders);
    }

    public String post(String signupEmail, String signupPassword, NexusGatewayApiEnum api, HashMap<String, String> context, Object object, boolean valid, List<NameValuePair> additionalHeaders) throws Exception {
        AccessToken token = NexusConnectApi.instance().getAccessTokenWithScope(
                valid ? api.getScope().getName() : Scope.getInvalidScope(api.getScope()).getName(),
                signupEmail, signupPassword);
        HttpPost httpPost = new HttpPost(initUrl(api, context));
        setHeaders(httpPost, token, additionalHeaders);
        if (api.getFormat() == "xml") {
            httpPost.setEntity(new StringEntity(TestUtil.parseObjectXml(object)));
            httpPost.addHeader("Accept", "application/xml");
        } else {
            httpPost.setEntity(new StringEntity(TestUtil.parseObject(object)));
            httpPost.addHeader("Accept", "application/json");
        }

        return parseResponse(post(httpPost, null), api, valid, null);
    }

    public String post(String signupEmail, String signupPassword, NexusGatewayApiEnum api, HashMap<String, String> context, Object object, boolean valid) throws Exception {
        return post(signupEmail, signupPassword, api, context, object, valid, null);
    }

    public String put(String signupEmail, String signupPassword, NexusGatewayApiEnum api, HashMap<String, String> context, Object object, List<NameValuePair> additionalHeaders) throws Exception {
        put(signupEmail, signupPassword, api, context, object, false,additionalHeaders);
        return put(signupEmail, signupPassword, api, context, object, true, additionalHeaders);
    }

    public String put(String signupEmail, String signupPassword, NexusGatewayApiEnum api, HashMap<String, String> context, Object object) throws Exception {
        return put(signupEmail, signupPassword, api, context, object, null);
    }

    public String put(String signupEmail, String signupPassword, NexusGatewayApiEnum api, HashMap<String, String> context, Object object, boolean valid, List<NameValuePair> additionalHeaders) throws Exception {
        AccessToken token = NexusConnectApi.instance().getAccessTokenWithScope(
                valid ? api.getScope().getName() : Scope.getInvalidScope(api.getScope()).getName(),
                signupEmail, signupPassword);
        HttpPut httpPut = new HttpPut(initUrl(api, context));
        setHeaders(httpPut, token, additionalHeaders);
        if(object != null) {
            httpPut.setEntity(new StringEntity(TestUtil.parseObject(object)));
        }
        else {
            httpPut.setEntity(new StringEntity("{}"));
        }

        return parseResponse(put(httpPut, null), api, valid, null);
    }

    public String put(String signupEmail, String signupPassword, NexusGatewayApiEnum api, HashMap<String, String> context, Object object, boolean valid) throws Exception {
        return put(signupEmail, signupPassword, api, context, object, valid, null);
    }

    public String get(NexusGatewayApiEnum api, HashMap<String, String> context, AccessToken token, boolean valid) throws Exception {
       return get(api, context, token, valid, null);
    }

    public String get(NexusGatewayApiEnum api, HashMap<String, String> context, AccessToken token, boolean valid, String errorInfo) throws Exception {
        HttpGet httpGet = new HttpGet(initUrl(api, context));
        setHeaders(httpGet, token);

        return parseResponse(get(httpGet, null), api, valid, errorInfo);
    }

    public String get(NexusGatewayApiEnum api, HashMap<String, String> context, AccessToken token, List<NameValuePair> additionalHeaders) throws Exception {
        HttpGet httpGet = new HttpGet(initUrl(api, context));
        setHeaders(httpGet, token, additionalHeaders);

        return parseResponse(get(httpGet, null), api);
    }

    public String delete(NexusGatewayApiEnum api, HashMap<String, String> context, AccessToken token, boolean valid) throws Exception {
       return delete(api, context, token, valid, null);
    }

    public String delete(NexusGatewayApiEnum api, HashMap<String, String> context, AccessToken token, boolean valid, String errorInfo) throws Exception {
        HttpDelete httpDelete = new HttpDelete(initUrl(api, context));
        setHeaders(httpDelete, token);

        return parseResponse(delete(httpDelete, null), api, valid, errorInfo);
    }

    public String post(NexusGatewayApiEnum api, HashMap<String, String> context, AccessToken token, Object object, boolean valid) throws Exception {
        return post(api, context, token, object, valid, null);
    }

    public String post(NexusGatewayApiEnum api, HashMap<String, String> context, AccessToken token, Object object, boolean valid, String errorInfo) throws Exception {
        HttpPost httpPost = new HttpPost(initUrl(api, context));
        setHeaders(httpPost, token);
        if (api.getFormat() == "xml") {
            httpPost.setEntity(new StringEntity(TestUtil.parseObjectXml(object)));
            httpPost.addHeader("Accept", "application/xml");
        } else {
            httpPost.setEntity(new StringEntity(TestUtil.parseObject(object)));
            httpPost.addHeader("Accept", "application/json");
        }

        return parseResponse(post(httpPost, null), api, valid, errorInfo);
    }

    public String post(NexusGatewayApiEnum api, HashMap<String, String> context, AccessToken token, String queryStr) throws Exception {
        HttpPost httpPost = new HttpPost(initUrl(api, context, queryStr));
        setHeaders(httpPost, token);
        httpPost.setEntity(new StringEntity(""));
        if (api.getFormat() == "xml") {
            httpPost.addHeader("Accept", "application/xml");
        } else {
            httpPost.addHeader("Accept", "application/json");
        }

        return parseResponse(post(httpPost, null), api, true, null);
    }

    public String post(NexusGatewayApiEnum api, HashMap<String, String> context, AccessToken token, String objectStr, boolean valid) throws Exception {
        HttpPost httpPost = new HttpPost(initUrl(api, context));
        setHeaders(httpPost, token);
        httpPost.setEntity(new StringEntity(objectStr == null ? "" : objectStr));
        if (api.getFormat() == "xml") {
            httpPost.addHeader("Accept", "application/xml");
        } else {
            httpPost.addHeader("Accept", "application/json");
        }

        return parseResponse(post(httpPost, null), api, valid, null);
    }

    public String post(NexusGatewayApiEnum api, HashMap<String, String> context, AccessToken token, String objectStr, boolean valid, String errorInfo) throws Exception {
        HttpPost httpPost = new HttpPost(initUrl(api, context));
        setHeaders(httpPost, token);
        httpPost.setEntity(new StringEntity(objectStr == null ? "" : objectStr));
        if (api.getFormat() == "xml") {
            httpPost.addHeader("Accept", "application/xml");
        } else {
            httpPost.addHeader("Accept", "application/json");
        }

        return parseResponse(post(httpPost, null), api, valid, errorInfo);
    }

    public String put(NexusGatewayApiEnum api, HashMap<String, String> context, AccessToken token, Object object, boolean valid) throws Exception {
        return put(api, context, token, object, valid, null);
    }

    public String put(NexusGatewayApiEnum api, HashMap<String, String> context, AccessToken token, Object object, boolean valid, String errorInfo) throws Exception {
        HttpPut httpPut = new HttpPut(initUrl(api, context));
        setHeaders(httpPut, token);
        httpPut.setEntity(new StringEntity(TestUtil.parseObject(object)));

        return parseResponse(put(httpPut, null), api, valid, errorInfo);
    }

    private String parseResponse(HttpResponse httpResponse, boolean valid, String error) throws Exception {
        String body = IOUtils.toString(httpResponse.getEntity().getContent());
        log.info("RESPONSE BODY: " + body);
        int status = httpResponse.getStatusLine().getStatusCode();
        if (!valid) {
            Assert.assertTrue(status == 409);
            Assert.assertTrue(body.contains(error));
        } else {
            if (status != 200 && status != 201) {
                throw new Exception(body);
            }
        }
        return body;
    }

    private String parseResponse(HttpResponse httpResponse, NucleusApi api, boolean valid) throws Exception {
        String body = IOUtils.toString(httpResponse.getEntity().getContent());
        log.info("RESPONSE BODY: " + body);
        int status = httpResponse.getStatusLine().getStatusCode();
        FailureType failureType = null;
        if (!valid) {
            Assert.assertTrue(status == 403);
            Assert.assertTrue(body.contains("scope_forbidden"));
        } else {
            if (status != 200 && status != 201) {
                throw new Exception(body);
            }
        }
        return body;
    }

    private String parseResponse(HttpResponse httpResponse, NexusGatewayApiEnum api, boolean valid, String errorInfo) throws Exception {
        String body = IOUtils.toString(httpResponse.getEntity().getContent());
        log.info("RESPONSE BODY: " + body);
        int status = httpResponse.getStatusLine().getStatusCode();
        FailureType failureType = null;
        if (!valid) {
            Assert.assertTrue(status == 403 || status == 409);
            if(errorInfo != null)
                Assert.assertTrue(body.contains(errorInfo));
        } else {
            if (status != 200 && status != 201) {
                throw new Exception(body);
            }
        }
        return body;
    }

    private String initUrl(NexusGatewayApiEnum api, HashMap<String, String> context) {
        return initUrl(api, context, null);
    }

    private String initUrl(NexusGatewayApiEnum api, HashMap<String, String> context, String queryString) {
        String url = TestUtil.BaseProxyURI() + "/proxy" + api.getUrl();

        for (Map.Entry<String, String> e : context.entrySet()) {
            url = url.replace("${" + e.getKey() + "}", e.getValue());
        }

        Assert.assertFalse(url.contains("${"), "url init fail: " + url);
        if(queryString != null) {
            url += ("?"+queryString);
        }
        return url;
    }

    private String parseResponse(HttpResponse httpResponse, NexusGatewayApiEnum api) throws Exception {
        String body = IOUtils.toString(httpResponse.getEntity().getContent());

        int status = httpResponse.getStatusLine().getStatusCode();
        FailureType failureType = null;

        if (status != 200 && status != 201) {
            throw new Exception(body);
        }
        return body;
    }


    private void setHeaders(HttpRequestBase requestBase, AccessToken token) {
        requestBase.setHeader("Authorization", token.getToken_type() + " " + token.getAccess_token());
        requestBase.setHeader("X-Source", "integration-tests");
        requestBase.setHeader("Nucleus-AdminUserId", "admin");

    }
    private void setHeaders(HttpRequestBase requestBase, AccessToken token, boolean expandResults) {
        requestBase.setHeader("Authorization", token.getToken_type() + " " + token.getAccess_token());
        requestBase.setHeader("X-Expand-Results", String.valueOf(expandResults));
    }

    private void setHeaders(HttpRequestBase requestBase, AccessToken token, List<NameValuePair> additonalHeaders) {
        requestBase.setHeader("Authorization", token.getToken_type() + " " + token.getAccess_token());
        requestBase.setHeader("X-Source", "integration-tests");
        requestBase.setHeader("Nucleus-AdminUserId", "admin");
        if(additonalHeaders != null) {
            for(NameValuePair nvp : additonalHeaders) {
                requestBase.setHeader(nvp.getName(), nvp.getValue());
            }
        }
    }
}
